﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
using AutoMapper;
using System.Web.Mvc;
using CashFlow.Entities.Properties;

namespace CashFlow.Entities.Models
{
	public class BillModel : IValidatableObject
	{
		private static SelectList recurrences;

		#region Constructors.
		static BillModel()
		{
			Mapper.CreateMap<BillModel, Bill>()
				.ForMember(
					dest => dest.Tenant,
					opt => opt.MapFrom(src => new Tenant(src.TenantId)))
				.ForMember(
					dest => dest.Amount,
					opt => opt.MapFrom(src => (src.BillType == 1 ? -1 : 1) * src.Amount))
				.ForMember(
					dest => dest.Recurrence,
					opt => opt.MapFrom(src => RecurrenceBase.GetNew(src.RecurrenceId)))
				.ForMember(
					dest => dest.Account,
					opt => opt.MapFrom(src => Account.GetDefault()));

			Mapper.CreateMap<Bill, BillModel>()
				.ForMember(
					dest => dest.TenantId,
					opt => opt.MapFrom(src => src.Tenant.Id))
				.ForMember(
					dest => dest.Amount,
					opt => opt.MapFrom(src => src.Amount < 0 ? -1 * src.Amount : src.Amount))
				.ForMember(
					dest => dest.RecurrenceId,
					opt => opt.MapFrom(src => src.Recurrence.Id))
				.ForMember(
					dest => dest.BillType,
					opt => opt.MapFrom(src => src.Amount < 0 ? 1 : 10));
			recurrences = new SelectList(RecurrenceBase.TypeList, "Item1", "Item2");
		}

		public static BillModel GetDefaultModel(Tenant tenant)
		{
			var bill = Bill.GetDefault(tenant);
			var model = (BillModel)bill;
			model.BillType = (int)Entities.BillType.Payment;
			return model;
		}
		#endregion

		#region Fields and Properties
		public string Id { get; set; }
		public string TenantId { get; set; }
		public string AccountId { get; set; }

		[Display(Name = "Pay to")]
		[Required(AllowEmptyStrings = false, ErrorMessage = "Please enter a description")]
		[StringLength(30, MinimumLength = 1, ErrorMessage = "The description cannot exceed 30 characters.")]
		public string PayeeName { get; set; }

		/// <summary>
		/// </summary>
		/// <remarks>
		/// 1 -payment, 10 - deposit.
		/// </remarks>
		[Display(Name = "Bill type")]
		[DefaultValue(1)]
		public int BillType { get; set; }

		[DataType(DataType.Date)]
		[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
		[Display(Name = "Next due date")]
		[Required(AllowEmptyStrings = false, ErrorMessage = "Please enter the next due date.")]
		public DateTime FirstDate { get; set; }

		[DataType(DataType.Date)]
		[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:d}")]
		[Display(Name = "Last date")]
		//TODO: vvs p2 LastDate >= FirstDate
		public DateTime? LastDate { get; set; }

		[Display(Name = "Amount")]
		[DataType(DataType.Currency)]
		[Required(AllowEmptyStrings = false, ErrorMessage = "Please enter a valid amount.")]
		//[Range(0, 100000000, ErrorMessage = "Amount should be between $0 and $100,000,000")]
		public double Amount { get; set; }

		[Display(Name = "Repeat")]
		public string RecurrenceId { get; set; }

		[Display(Name = "Details")]
		[StringLength(300, ErrorMessage = "The details cannot exceed 300 characters.")]
		public string Details { get; set; }

		public SelectList RecurrenceTypes
		{
			get
			{
				return recurrences;
			}
		}
		#endregion

		#region Mappers
		public static explicit operator Bill(BillModel model)
		{
			return Mapper.Map<BillModel, Bill>(model);
		}

		public static explicit operator BillModel(Bill entity)
		{
			return Mapper.Map<Bill, BillModel>(entity);
		}
		#endregion

		/// <summary>
		/// Determines whether this model is valid.
		/// </summary>
		/// <param name="context">The validation context.</param>
		/// <returns>A collection that holds failed-validation information.</returns>
		public IEnumerable<ValidationResult> Validate(ValidationContext context)
		{
			if (LastDate.HasValue && LastDate.Value.CompareTo(FirstDate) < 0)
				yield return new ValidationResult(Resources.ErrorLastDateGTFirstDate, new string[] {"LastDate"});
		}
	}
}
